Imports System
Imports System.Data
Imports System.Collections.Generic

Imports Framework

<Serializable(), CLSCompliant(True)> _
Partial Public Class CProductList : Inherits List(Of CProduct)

#Region "Constructors"
    'Basic constructor
    Public Sub New()
        MyBase.New()  
    End Sub
    
    'More efficient memory-allocation if size is known
    Public Sub New(ByVal capacity As Integer)
        MyBase.New(capacity)  
    End Sub
    
    'Shares the index (if its already been computed)
    Public Sub New(ByVal list As CProductList)
        MyBase.New(list)
        _index = list._index 
    End Sub

    'Generic list (eg. from paging control), have to assume type
    Public Sub New(ByVal list As IList)
        MyBase.New(list.Count)
        For Each i As CProduct In list
            MyBase.Add(i)
        Next
    End Sub
#End Region

#Region "Top/Bottom/Page"
    Public Function Top(ByVal count As Integer) As CProductList
        If count >= Me.Count Then Return Me
        Return New CProductList(CUtilities.Page(Me, count, 0))
    End Function
    Public Function Bottom(ByVal count As Integer) As CProductList
        If count > Me.Count Then count = Me.Count
        Return New CProductList(Me.GetRange(Me.Count - count - 1, count))
    End Function
    Public Function Page(pageSize As Integer, pageIndex As Integer) As CProductList
        Return New CProductList( CUtilities.Page(Me, pageSize, pageIndex) )
    End Function
#End Region

#Region "BulkEditLogic"
    Public Function HaveSameValue(ByVal propertyName As String) As Boolean
        Return CReflection.HaveSameValue(Me, propertyName)
    End Function
    Public Sub SetSameValue(ByVal propertyName As String, ByVal value As Object)
        CReflection.SetSameValue(Me, propertyName, value)
    End Sub
#End Region

#Region "SortBy"
    'Public
    Public Function SortBy(ByVal propertyName As String, Optional ByVal descending As Boolean = False) As CProductList
        Dim copy As New CProductList(Me)
        If Me.Count = 0 Then
            Return copy
        End If
        copy.Sort(New CProductList_SortBy(propertyName, descending, Me))
        Return copy
    End Function
    'Private 
    Private Class CProductList_SortBy : Inherits CReflection.GenericSortBy : Implements IComparer(Of CProduct)
        Public Sub New(ByVal propertyName As String, ByVal descending As Boolean, ByVal list As IList)
            MyBase.New(propertyName, descending, list)
        End Sub
        Public Overloads Function Compare(ByVal x As CProduct, ByVal y As CProduct) As Integer Implements IComparer(Of CProduct).Compare
            Return MyBase.Compare(x, y)
        End Function
    End Class
#End Region

#Region "SaveAll/DeleteAll"
    'Use default connection (may be overridden in base class)
    Public Sub SaveAll()
        If Me.Count = 0 Then Exit Sub
        SaveAll(Me(0).DataSrc)
    End Sub
    Public Sub DeleteAll()
        If Me.Count = 0 Then Exit Sub
        DeleteAll(Me(0).DataSrc)
    End Sub
    
    'Use connection supplied
    Public Sub SaveAll(dataSrc as CDatasrc)
        dataSrc.BulkSave(Me)
    End Sub
    Public Sub DeleteAll(dataSrc as CDatasrc)
        dataSrc.BulkDelete(Me)
    End Sub

    'Use transaction supplied
    Public Sub SaveAll(ByVal txOrNull As IDbTransaction)
        For Each i As CProduct In Me
            i.Save(txOrNull)
        Next
    End Sub
    Public Sub DeleteAll(ByVal txOrNull As IDbTransaction)
        For Each i As CProduct In Me
            i.Delete(txOrNull)
        Next
    End Sub

    'Use a specified isolation level
    Public Sub SaveAll(ByVal txIsolationLevel As IsolationLevel)
        If Me.Count = 0 Then Exit Sub
        SaveAll(Me(0).DataSrc, txIsolationLevel)
    End Sub
    Public Sub DeleteAll(ByVal txIsolationLevel As IsolationLevel)
        If Me.Count = 0 Then Exit Sub
        DeleteAll(Me(0).DataSrc, txIsolationLevel)
    End Sub
    
    'Use a specified connection and isolation level
    Public Sub SaveAll(ByVal dataSrc as CDatasrc, ByVal txIsolationLevel As IsolationLevel)
        dataSrc.BulkSave(Me, txIsolationLevel)
    End Sub
    Public Sub DeleteAll(ByVal dataSrc as CDatasrc, ByVal txIsolationLevel As IsolationLevel)
        dataSrc.BulkDelete(Me, txIsolationLevel)
    End Sub
#End Region

#Region "List of Ids"
    Private m_ids As List(Of Integer)
    Public ReadOnly Property Ids() As List(Of Integer)
        Get
            If m_ids Is Nothing Then
                Dim list As New List(Of Integer)(Me.Count)
                For Each i As CProduct In Me
                    list.Add(i.ProductId)
                Next
                m_ids = list
            End If
            Return m_ids
        End Get
    End Property
    Public Function GetByIds(ByVal ids As List(Of Integer)) As CProductList
        Dim list As New CProductList(ids.Count)
        For Each id As Integer In ids
            If GetById(id) IsNot Nothing Then
                list.Add(GetById(id))
            End If
        Next
        Return list
    End Function
#End Region

#Region "Cache-Control"
    'Main Logic
    Public Shadows Sub Add(ByVal item As CProduct)
        If Not IsNothing(_index) Then
            If Not _index.ContainsKey(item.ProductId) Then
                _index(item.ProductId) = item
            End If
        End If
        MyBase.Add(item)
    End Sub
    Public Shadows Sub Remove(ByVal item As CProduct)
        If Not IsNothing(_index) Then
            If _index.ContainsKey(item.ProductId) Then
                _index.Remove(item.ProductId)
            End If
        End If
        MyBase.Remove(item)
    End Sub
    
    'Supplementary List Overloads
    Public Shadows Sub Add(ByVal itemsToAdd As IList(Of CProduct))
        For Each i As CProduct In itemsToAdd
            Add(i)
        Next
    End Sub
    Public Shadows Sub Remove(ByVal itemsToRemove As IList(Of CProduct))
        For Each i As CProduct In itemsToRemove
            Remove(i)
        Next
    End Sub
#End Region

#Region "Main Index (on ProductId)"
    'Only uncomment if type is NOT an Integer (e.g. string/guid)
    'Default Public Overloads ReadOnly Property Item(ByVal productId As Integer) As CProduct
    '    Get
    '        Return GetById(productId)
    '    End Get
    'End Property
    Public Function GetById(ByVal [productId] As Integer) As CProduct
        Dim c As CProduct = Nothing
        Index.TryGetValue([productId], c)
        Return c
    End Function
    <NonSerialized()> _
    Private _index As Dictionary(Of Integer, CProduct)
    Private ReadOnly Property Index() As Dictionary(Of Integer, CProduct)
        Get
            If Not IsNothing(_index) Then
                If _index.Count = Me.Count Then
                    Return _Index
                End If
            End If
            _index = New Dictionary(Of Integer, CProduct)(Me.Count)
            For Each i As CProduct in Me
                _index(i.ProductId) = i
            Next
            Return _index
        End Get
    End Property
#End Region
    
#Region "Foreign-Key Indices (Subsets)"
    'Index by ProductTypeId
    Public Function GetByTypeId(ByVal typeId As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByTypeId.TryGetValue(typeId, temp) Then
            temp = New CProductList()
            IndexByTypeId(typeId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByTypeId As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexByTypeId() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexByTypeId) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductTypeId, temp) Then
                        temp = New CProductList()
                        index(i.ProductTypeId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByTypeId = index
            End If
            Return _indexByTypeId
        End Get
    End Property

    'Index by ProductSpeakerId
    Public Function GetBySpeakerId(ByVal speakerId As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexBySpeakerId.TryGetValue(speakerId, temp) Then
            temp = New CProductList()
            IndexBySpeakerId(speakerId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexBySpeakerId As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexBySpeakerId() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexBySpeakerId) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductSpeakerId, temp) Then
                        temp = New CProductList()
                        index(i.ProductSpeakerId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexBySpeakerId = index
            End If
            Return _indexBySpeakerId
        End Get
    End Property

    'Index by ProductSpeaker2Id
    Public Function GetBySpeaker2Id(ByVal speaker2Id As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexBySpeaker2Id.TryGetValue(speaker2Id, temp) Then
            temp = New CProductList()
            IndexBySpeaker2Id(speaker2Id) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexBySpeaker2Id As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexBySpeaker2Id() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexBySpeaker2Id) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductSpeaker2Id, temp) Then
                        temp = New CProductList()
                        index(i.ProductSpeaker2Id) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexBySpeaker2Id = index
            End If
            Return _indexBySpeaker2Id
        End Get
    End Property

    'Index by ProductLanguageId
    Public Function GetByLanguageId(ByVal languageId As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByLanguageId.TryGetValue(languageId, temp) Then
            temp = New CProductList()
            IndexByLanguageId(languageId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByLanguageId As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexByLanguageId() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexByLanguageId) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductLanguageId, temp) Then
                        temp = New CProductList()
                        index(i.ProductLanguageId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByLanguageId = index
            End If
            Return _indexByLanguageId
        End Get
    End Property

    'Index by ProductLocationId
    Public Function GetByLocationId(ByVal locationId As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByLocationId.TryGetValue(locationId, temp) Then
            temp = New CProductList()
            IndexByLocationId(locationId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByLocationId As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexByLocationId() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexByLocationId) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductLocationId, temp) Then
                        temp = New CProductList()
                        index(i.ProductLocationId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByLocationId = index
            End If
            Return _indexByLocationId
        End Get
    End Property

    'Index by ProductBelongsToProductId
    Public Function GetByBelongsToProductId(ByVal belongsToProductId As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByBelongsToProductId.TryGetValue(belongsToProductId, temp) Then
            temp = New CProductList()
            IndexByBelongsToProductId(belongsToProductId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByBelongsToProductId As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByBelongsToProductId() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByBelongsToProductId) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductBelongsToProductId, temp) Then
                        temp = New CProductList()
                        index(i.ProductBelongsToProductId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByBelongsToProductId = index
            End If
            Return _indexByBelongsToProductId
        End Get
    End Property

    'Index by ProductPaypalButtonId
    Public Function GetByPaypalButtonId(ByVal paypalButtonId As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByPaypalButtonId.TryGetValue(paypalButtonId, temp) Then
            temp = New CProductList()
            IndexByPaypalButtonId(paypalButtonId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByPaypalButtonId As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByPaypalButtonId() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByPaypalButtonId) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductPaypalButtonId, temp) Then
                        temp = New CProductList()
                        index(i.ProductPaypalButtonId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByPaypalButtonId = index
            End If
            Return _indexByPaypalButtonId
        End Get
    End Property

    'Index by ProductIsActive
    Public Function GetByIsActive(ByVal isActive As Boolean) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByIsActive.TryGetValue(isActive, temp) Then
            temp = New CProductList()
            IndexByIsActive(isActive) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByIsActive As Dictionary(Of Boolean, CProductList)
    Private ReadOnly Property IndexByIsActive() As Dictionary(Of Boolean, CProductList)
        Get
            If IsNothing(_indexByIsActive) Then
                'Instantiate
                Dim index As New Dictionary(Of Boolean, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductIsActive, temp) Then
                        temp = New CProductList()
                        index(i.ProductIsActive) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByIsActive = index
            End If
            Return _indexByIsActive
        End Get
    End Property

    'Index by ProductScribeId
    Public Function GetByScribeId(ByVal scribeId As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByScribeId.TryGetValue(scribeId, temp) Then
            temp = New CProductList()
            IndexByScribeId(scribeId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByScribeId As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexByScribeId() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexByScribeId) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductScribeId, temp) Then
                        temp = New CProductList()
                        index(i.ProductScribeId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByScribeId = index
            End If
            Return _indexByScribeId
        End Get
    End Property

    'Index by ProductImageScribeId
    Public Function GetByImageScribeId(ByVal imageScribeId As Byte) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByImageScribeId.TryGetValue(imageScribeId, temp) Then
            temp = New CProductList()
            IndexByImageScribeId(imageScribeId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByImageScribeId As Dictionary(Of Byte, CProductList)
    Private ReadOnly Property IndexByImageScribeId() As Dictionary(Of Byte, CProductList)
        Get
            If IsNothing(_indexByImageScribeId) Then
                'Instantiate
                Dim index As New Dictionary(Of Byte, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductImageScribeId, temp) Then
                        temp = New CProductList()
                        index(i.ProductImageScribeId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByImageScribeId = index
            End If
            Return _indexByImageScribeId
        End Get
    End Property

    'Index by ProductVimeoId
    Public Function GetByVimeoId(ByVal vimeoId As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByVimeoId.TryGetValue(vimeoId, temp) Then
            temp = New CProductList()
            IndexByVimeoId(vimeoId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByVimeoId As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByVimeoId() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByVimeoId) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductVimeoId, temp) Then
                        temp = New CProductList()
                        index(i.ProductVimeoId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByVimeoId = index
            End If
            Return _indexByVimeoId
        End Get
    End Property

    'Index by ProductYouTubeId
    Public Function GetByYouTubeId(ByVal youTubeId As String) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByYouTubeId.TryGetValue(youTubeId, temp) Then
            temp = New CProductList()
            IndexByYouTubeId(youTubeId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByYouTubeId As Dictionary(Of String, CProductList)
    Private ReadOnly Property IndexByYouTubeId() As Dictionary(Of String, CProductList)
        Get
            If IsNothing(_indexByYouTubeId) Then
                'Instantiate
                Dim index As New Dictionary(Of String, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductYouTubeId, temp) Then
                        temp = New CProductList()
                        index(i.ProductYouTubeId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByYouTubeId = index
            End If
            Return _indexByYouTubeId
        End Get
    End Property

    'Index by ProductSmashwordsId
    Public Function GetBySmashwordsId(ByVal smashwordsId As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexBySmashwordsId.TryGetValue(smashwordsId, temp) Then
            temp = New CProductList()
            IndexBySmashwordsId(smashwordsId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexBySmashwordsId As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexBySmashwordsId() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexBySmashwordsId) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductSmashwordsId, temp) Then
                        temp = New CProductList()
                        index(i.ProductSmashwordsId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexBySmashwordsId = index
            End If
            Return _indexBySmashwordsId
        End Get
    End Property

    'Index by ProductAmazonId
    Public Function GetByAmazonId(ByVal amazonId As String) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByAmazonId.TryGetValue(amazonId, temp) Then
            temp = New CProductList()
            IndexByAmazonId(amazonId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByAmazonId As Dictionary(Of String, CProductList)
    Private ReadOnly Property IndexByAmazonId() As Dictionary(Of String, CProductList)
        Get
            If IsNothing(_indexByAmazonId) Then
                'Instantiate
                Dim index As New Dictionary(Of String, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductAmazonId, temp) Then
                        temp = New CProductList()
                        index(i.ProductAmazonId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByAmazonId = index
            End If
            Return _indexByAmazonId
        End Get
    End Property

    'Index by ProductCSBookId
    Public Function GetByCSBookIds(ByVal cSBookId As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByCSBookIds.TryGetValue(cSBookId, temp) Then
            temp = New CProductList()
            IndexByCSBookIds(cSBookId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByCSBookIds As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByCSBookIds() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByCSBookIds) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct In Me
                    If i.ProductCSBookId > 0 Then
                        If Not index.TryGetValue(i.ProductCSBookId, temp) Then
                            temp = New CProductList()
                            index(i.ProductCSBookId) = temp
                        End If
                        temp.Add(i)
                    End If
                    If i.ProductCSBook2Id > 0 Then
                        If Not index.TryGetValue(i.ProductCSBook2Id, temp) Then
                            temp = New CProductList()
                            index(i.ProductCSBook2Id) = temp
                        End If
                        temp.Add(i)
                    End If
                    If i.ProductCSBook3Id > 0 Then
                        If Not index.TryGetValue(i.ProductCSBook3Id, temp) Then
                            temp = New CProductList()
                            index(i.ProductCSBook3Id) = temp
                        End If
                        temp.Add(i)
                    End If

                    If i.HasParent Then
                        Dim p As CProduct = i.BelongsTo
                        If p.ProductCSBookId > 0 Then
                            If Not index.TryGetValue(p.ProductCSBookId, temp) Then
                                temp = New CProductList()
                                index(p.ProductCSBookId) = temp
                            End If
                            temp.Add(i)
                        End If
                        If p.ProductCSBook2Id > 0 Then
                            If Not index.TryGetValue(p.ProductCSBook2Id, temp) Then
                                temp = New CProductList()
                                index(p.ProductCSBook2Id) = temp
                            End If
                            temp.Add(i)
                        End If
                        If p.ProductCSBook3Id > 0 Then
                            If Not index.TryGetValue(p.ProductCSBook3Id, temp) Then
                                temp = New CProductList()
                                index(p.ProductCSBook3Id) = temp
                            End If
                            temp.Add(i)
                        End If
                    End If
                Next

                'Store
                _indexByCSBookIds = index
            End If
            Return _indexByCSBookIds
        End Get
    End Property

    Public Function GetByCSBookId(ByVal cSBookId As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByCSBookId.TryGetValue(cSBookId, temp) Then
            temp = New CProductList()
            IndexByCSBookId(cSBookId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByCSBookId As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByCSBookId() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByCSBookId) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductCSBookId, temp) Then
                        temp = New CProductList()
                        index(i.ProductCSBookId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByCSBookId = index
            End If
            Return _indexByCSBookId
        End Get
    End Property

    'Index by ProductCSBook2Id
    Public Function GetByCSBook2Id(ByVal cSBook2Id As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByCSBook2Id.TryGetValue(cSBook2Id, temp) Then
            temp = New CProductList()
            IndexByCSBook2Id(cSBook2Id) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByCSBook2Id As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByCSBook2Id() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByCSBook2Id) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductCSBook2Id, temp) Then
                        temp = New CProductList()
                        index(i.ProductCSBook2Id) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByCSBook2Id = index
            End If
            Return _indexByCSBook2Id
        End Get
    End Property

    'Index by ProductCSBook3Id
    Public Function GetByCSBook3Id(ByVal cSBook3Id As Integer) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByCSBook3Id.TryGetValue(cSBook3Id, temp) Then
            temp = New CProductList()
            IndexByCSBook3Id(cSBook3Id) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByCSBook3Id As Dictionary(Of Integer, CProductList)
    Private ReadOnly Property IndexByCSBook3Id() As Dictionary(Of Integer, CProductList)
        Get
            If IsNothing(_indexByCSBook3Id) Then
                'Instantiate
                Dim index As New Dictionary(Of Integer, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductCSBook3Id, temp) Then
                        temp = New CProductList()
                        index(i.ProductCSBook3Id) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByCSBook3Id = index
            End If
            Return _indexByCSBook3Id
        End Get
    End Property

    'Index by ProductYouTubePlaylistId
    Public Function GetByYouTubePlaylistId(ByVal youTubePlaylistId As String) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByYouTubePlaylistId.TryGetValue(youTubePlaylistId, temp) Then
            temp = New CProductList()
            IndexByYouTubePlaylistId(youTubePlaylistId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByYouTubePlaylistId As Dictionary(Of String, CProductList)
    Private ReadOnly Property IndexByYouTubePlaylistId() As Dictionary(Of String, CProductList)
        Get
            If IsNothing(_indexByYouTubePlaylistId) Then
                'Instantiate
                Dim index As New Dictionary(Of String, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductYouTubePlaylistId, temp) Then
                        temp = New CProductList()
                        index(i.ProductYouTubePlaylistId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByYouTubePlaylistId = index
            End If
            Return _indexByYouTubePlaylistId
        End Get
    End Property

    'Index by ProductVimeoChannelId
    Public Function GetByVimeoChannelId(ByVal vimeoChannelId As String) As CProductList
        Dim temp As CProductList = Nothing
        If Not IndexByVimeoChannelId.TryGetValue(vimeoChannelId, temp) Then
            temp = New CProductList()
            IndexByVimeoChannelId(vimeoChannelId) = temp
        End If
        Return temp
    End Function
    <NonSerialized()> _
    Private _indexByVimeoChannelId As Dictionary(Of String, CProductList)
    Private ReadOnly Property IndexByVimeoChannelId() As Dictionary(Of String, CProductList)
        Get
            If IsNothing(_indexByVimeoChannelId) Then
                'Instantiate
                Dim index As New Dictionary(Of String, CProductList)()

                'Populate
                Dim temp As CProductList = Nothing
                For Each i As CProduct in Me
                    If Not index.TryGetValue(i.ProductVimeoChannelId, temp) Then
                        temp = New CProductList()
                        index(i.ProductVimeoChannelId) = temp
                    End If
                    temp.Add(i)
                Next

                'Store
                _indexByVimeoChannelId = index
            End If
            Return _indexByVimeoChannelId
        End Get
    End Property

#End Region


#Region "Move Up/Down"
    Public Sub MoveUp(ByVal s As CProduct)
        Move(s, -1)
    End Sub
    Public Sub MoveDown(ByVal s As CProduct)
        Move(s, 1)
    End Sub
    Public Sub SortAlphabetically
        For Each i As CProduct In Me
            i.ProductBelongsToSortOrder = 0
        Next
        Me.SaveAll()
        CProduct.Cache = Nothing
    End Sub

    'Private
    Private Sub Move(ByVal s As CProduct, ByVal change As Integer)
        If IsNothing(s) Then Exit Sub
        Dim index As Integer = Me.IndexOf(s) + change
        If index < 0 Then Exit Sub
        If index > Me.Count - 1 Then Exit Sub

        'Modify a copy of the array for threadsafety
        Dim dd As New CProductList(Me.Count)
        dd.AddRange(Me)
        With dd
            .Remove(s)
            .Insert(index, s)
            .ResetOrdinals()
        End With

        Me.SaveAll()
        CProduct.Cache = Nothing
    End Sub
    Private Sub ResetOrdinals()
        For i As Integer = 0 To Me.Count - 1
            Me(i).ProductBelongsToSortOrder = i
        Next
    End Sub
#End Region
End Class